package com.gitee.wsl.io

import com.gitee.wsl.api.closeQuietly
import com.gitee.wsl.ext.string.div
import com.gitee.wsl.struct.generator.Generator
import kotlinx.io.RawSink
import kotlinx.io.RawSource
import kotlinx.io.Sink
import kotlinx.io.Source
import kotlinx.io.buffered
import kotlinx.io.files.FileSystem
import kotlinx.io.files.Path
import kotlinx.io.files.SystemFileSystem
import kotlinx.io.files.SystemTemporaryDirectory
import kotlinx.io.readString
import kotlinx.io.writeString

class File(
    override val path: Path,
    override val fileSystem: FileSystem = SystemFileSystem
): PathAble{

    constructor(path:String):this(Path(path))

    fun length() = size

    val extension:String get() = path.name.substringAfterLast('.')

    val directoryPath: String? get() = parent?.name

    val nameWithoutExtension:String get() = path.name.substringBeforeLast('.')

    fun read(block:  RawSource.()->Unit) = path.source(fileSystem,block)

    fun write(append: Boolean = false,block:  RawSink.()->Unit) = path.sink(fileSystem,append,block)

    fun copyTo(destFile: File){}

    fun readSource() = path.sourceBuffered()

    fun readBuffered(block: Source.()->Unit) = path.sourceBuffered(fileSystem,block)

    fun writeSink(append: Boolean = false) = path.sinkBuffered()

    fun writeBuffered(append: Boolean = false,block: Sink.()->Unit) = path.sinkBuffered(fileSystem,append,block)

    override fun copyTo(destDir: Dir) {
        val copyToFile = destDir / this.name
        if(copyToFile.exists()) return
        copyToFile.sinkBuffered().transferFrom(this.readSource())
    }

    fun renameTo(destDir:File) = fileSystem.atomicMove(path,destDir.path)

    override fun toString(): String = path.toString()

    fun readText() = readSource().readString()

    fun writeText(text:String) = writeBuffered {  writeString(text) }

    override fun createIfNoExists(): Boolean {
        if(parent?.createIfNoExists() == false) return false
        if(!isExits)
            fileSystem.sink(path).closeQuietly()
        return true
    }

    fun setLastModified(timestamp: Long) {
    }

    fun readLines() = readSource().use {
        buildList {
            while (true) {
                add(readlnOrNull() ?: break)
            }
        }
    }

    companion object{
        fun crateTempFile(pref:String = "tmp") = File(Path(SystemTemporaryDirectory, Generator.FileName(9)+".$pref"))
    }

}

fun File(dir: Dir,name:String) = File(dir.path / name)

fun File(dir: String,name:String) = File(dir / name)


fun Path.toFile() = File(this)

fun File.createNewFile() {
    this.delete()
    this.createIfNoExists()
}